package cn.itsource.ymcc.service.impl;

import cn.itsource.ymcc.domain.Course;
import cn.itsource.ymcc.domain.CourseMarket;
import cn.itsource.ymcc.domain.CourseOrder;
import cn.itsource.ymcc.domain.CourseOrderItem;
import cn.itsource.ymcc.dto.*;
import cn.itsource.ymcc.exception.GlobleException;
import cn.itsource.ymcc.feign.CourseFeign;
import cn.itsource.ymcc.mapper.CourseOrderMapper;
import cn.itsource.ymcc.result.JSONResult;
import cn.itsource.ymcc.service.ICourseOrderItemService;
import cn.itsource.ymcc.service.ICourseOrderService;
import cn.itsource.ymcc.util.AssertUtil;
import cn.itsource.ymcc.util.CodeGenerateUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Eric Chen
 * @since 2022-07-22
 */
@Service
public class CourseOrderServiceImpl extends ServiceImpl<CourseOrderMapper, CourseOrder> implements ICourseOrderService {
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    @Autowired
    private RedisTemplate<String,String> template;
    @Autowired
    private CourseFeign courseFeign;
    @Autowired
    private ICourseOrderItemService courseOrderItemService;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private RedissonClient redissonClient;
    @Override
    public String placeOrder(OrderDto dto) {
        Long loginId = 3l;
        List<Long> ids = dto.getCourseIds();
        String join = StringUtils.join(ids, ",");
        String key = loginId + ":" + join;
        // 判断 redis是否包含key
        String s = template.opsForValue().get(key);
        AssertUtil.isNotNull(s,"非法，重新下单");
        AssertUtil.isEquals(s,dto.getToken(),"token不对，重新下单");

        JSONResult result = courseFeign.info(join);

        String s1 = JSON.toJSONString(result.getData());
        CourseOrderDto courseOrderDto = JSON.parseObject(s1, CourseOrderDto.class);

        //设置order表
        String s2 = CodeGenerateUtils.generateOrderSn(loginId);
        Date date = new Date();
        CourseOrder order = new CourseOrder();
        order.setCreateTime(date);
        order.setOrderNo(s2);
        order.setStatusOrder(0);
        order.setTotalAmount(courseOrderDto.getTotalAmount());
        order.setUserId(loginId);
        order.setVersion(0);
        order.setPayType(dto.getPayType());
        //insert(order);

        StringBuilder builder = new StringBuilder();
        builder.append("buy");
        // 设置CourseOrderItem表
        List<CourseInfo> courseInfos = courseOrderDto.getCourseInfos();

        for (CourseInfo courseInfo : courseInfos) {
            Course course = courseInfo.getCourse();
            CourseMarket courseMarket = courseInfo.getCourseMarket();

            CourseOrderItem courseOrderItem = new CourseOrderItem();
            courseOrderItem.setAmount(courseMarket.getPrice());
            courseOrderItem.setCount(1);
            courseOrderItem.setCourseId(course.getId());
            courseOrderItem.setCourseName(course.getName());
            courseOrderItem.setCoursePic(course.getPic());
            //courseOrderItem.setOrderId(order.getId());
            courseOrderItem.setOrderNo(order.getOrderNo());
            courseOrderItem.setVersion(0);
            courseOrderItem.setCreateTime(date);
            //总数量相加
            order.setTotalCount(order.getTotalCount() + courseOrderItem.getCount());
            //拼接标题每个课程内容
            order.setTitle(builder.append(course.getName()).toString());
            //courseOrderItemService.insert(courseOrderItem);
            order.getCourseOrderItems().add(courseOrderItem);

        }
        //updateById(order);

        Map<String, Object> map = new HashMap<>();

        map.put("loginId",loginId);
        map.put("courseId", join);
        String s4 = JSON.toJSONString(map);

        //保存支付订单信息
        PayOrderDataDto dataDto = new PayOrderDataDto(
                order.getTotalAmount(),
                order.getPayType(),
                order.getOrderNo(),
                order.getUserId(),
                s4,
                order.getTitle(),
                order.getId());
        //转成mess信息对象
        String s3 = JSON.toJSONString(dataDto);
        Message<String> message = MessageBuilder.withPayload(s3).build();


        //发送事务消息
        // mes用来传递支付订单信息， arg传递订单和明细信息
        TransactionSendResult result1 = rocketMQTemplate.sendMessageInTransaction(
                "PayMesGroup",
                "payorder-topic:payorder-tag", message, order);

        //获取本地事务执行状态
        LocalTransactionState state = result1.getLocalTransactionState();
        //消息发送状态
        SendStatus sendStatus = result1.getSendStatus();

        //事务执行失败需走下
        if (state != LocalTransactionState.COMMIT_MESSAGE ||
                sendStatus != SendStatus.SEND_OK){
            throw new GlobleException("下单失败");
        }

//        //发送延迟消息mq检查是否支付超时
//        SendResult sendResult = rocketMQTemplate.syncSend(
//                "paytimeout-topic:paytimeout-tag",
//                MessageBuilder.withPayload(order.getOrderNo()).build(),
//                2000,
//                6 // 10秒
//        );


        //template.delete(key);

        return order.getOrderNo();
    }


    //mq调用此方法
    @Override
    public void saveOrderAndItem(CourseOrder courseOrder) {
        insert(courseOrder);
        List<CourseOrderItem> items = courseOrder.getCourseOrderItems();
        items.forEach(item->{
            item.setOrderNo(courseOrder.getOrderNo());
            item.setOrderId(courseOrder.getId());
            courseOrderItemService.insert(item);
        });
    }


    //mq调用方法查询是否保存成功
    @Override
    public CourseOrder selectByOrderNo(String orderNo) {
        EntityWrapper<CourseOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no",orderNo);

        return selectOne(wrapper);
    }
    //更新状态
    @Override
    public void upDateState(PayResultDto payResultDto) {
        CourseOrder courseOrder = selectByOrderNo(payResultDto.getOrderNo());
        if (courseOrder.getStatusOrder() != 0){
            return;
        }
        int state = payResultDto.isPaySuccess() ? 1 : 3;
        courseOrder.setStatusOrder(state);
        courseOrder.setUpdateTime(new Date());
        updateById(courseOrder);
    }

    @Override
    public void cancel(String s) {
        CourseOrder courseOrder = selectByOrderNo(s);
        if (courseOrder.getStatusOrder() != 0)return;

        //取消订单
        courseOrder.setStatusOrder(2);
        courseOrder.setUpdateTime(new Date());
        updateById(courseOrder);

        //如果是秒杀订单退信号量添加type字段，秒杀id添加字段
        //TODO

    }

    @Override
    public String killPlaceOrder(KillDto dto) {

        Long loginId = 3l;
        //分布式锁与延迟消息共享锁
        String orderKey = "order:"+loginId+":"+dto.getOrderNo();
        RLock lock = redissonClient.getLock("lock:" + orderKey);
        try {
            KillOrderDto killOrderDto = (KillOrderDto) redisTemplate.opsForValue().get(orderKey);
            AssertUtil.isNotNull(killOrderDto,"无此订单");

            //String join = StringUtils.join(ids, ",");
            Long courseId = killOrderDto.getCourseId();
            String key = loginId + ":" + courseId;
            // 判断 redis是否包含key
            String s = template.opsForValue().get(key);
            AssertUtil.isNotNull(s,"非法，重新下单");
            AssertUtil.isEquals(s,dto.getToken(),"token不对，重新下单");

            JSONResult result = courseFeign.infoKill(courseId.toString(),dto.getOrderNo());

            String s1 = JSON.toJSONString(result.getData());
            CourseOrderDto courseOrderDto = JSON.parseObject(s1, CourseOrderDto.class);

            //设置order表
            Date date = new Date();
            CourseOrder order = new CourseOrder();
            order.setCreateTime(date);
            order.setOrderNo(dto.getOrderNo());
            order.setStatusOrder(0);
            order.setTotalAmount(killOrderDto.getTotalAmount());
            order.setUserId(loginId);
            order.setVersion(0);
            order.setPayType(dto.getPayType());
            //insert(order);

            StringBuilder builder = new StringBuilder();
            builder.append("buy");
            // 设置CourseOrderItem表
            List<CourseInfo> courseInfos = courseOrderDto.getCourseInfos();

            for (CourseInfo courseInfo : courseInfos) {
                Course course = courseInfo.getCourse();
                CourseMarket courseMarket = courseInfo.getCourseMarket();

                CourseOrderItem courseOrderItem = new CourseOrderItem();
                courseOrderItem.setAmount(courseMarket.getPrice());
                courseOrderItem.setCount(1);
                courseOrderItem.setCourseId(course.getId());
                courseOrderItem.setCourseName(course.getName());
                courseOrderItem.setCoursePic(course.getPic());
                //courseOrderItem.setOrderId(order.getId());
                courseOrderItem.setOrderNo(order.getOrderNo());
                courseOrderItem.setVersion(0);
                courseOrderItem.setCreateTime(date);
                //总数量相加
                order.setTotalCount(order.getTotalCount() + courseOrderItem.getCount());
                //拼接标题每个课程内容
                order.setTitle(builder.append(course.getName()).toString());
                //courseOrderItemService.insert(courseOrderItem);
                order.getCourseOrderItems().add(courseOrderItem);

            }
            //updateById(order);

            Map<String, Object> map = new HashMap<>();

            map.put("loginId",loginId);
            map.put("courseId", courseId);
            String s4 = JSON.toJSONString(map);

            //保存支付订单信息
            PayOrderDataDto dataDto = new PayOrderDataDto(
                    order.getTotalAmount(),
                    order.getPayType(),
                    order.getOrderNo(),
                    order.getUserId(),
                    s4,
                    order.getTitle(),
                    order.getId());
            //转成mess信息对象
            String s3 = JSON.toJSONString(dataDto);
            Message<String> message = MessageBuilder.withPayload(s3).build();


            //发送事务消息
            // mes用来传递支付订单信息， arg传递订单和明细信息
            TransactionSendResult result1 = rocketMQTemplate.sendMessageInTransaction(
                    "PayMesGroup",
                    "payorder-topic:payorder-tag", message, order);

            //获取本地事务执行状态
            LocalTransactionState state = result1.getLocalTransactionState();
            //消息发送状态
            SendStatus sendStatus = result1.getSendStatus();

            //事务执行失败需走下
            if (state != LocalTransactionState.COMMIT_MESSAGE ||
                    sendStatus != SendStatus.SEND_OK){
                throw new GlobleException("下单失败");
            }

//        //发送延迟消息mq检查是否支付超时
//        SendResult sendResult = rocketMQTemplate.syncSend(
//                "paytimeout-topic:paytimeout-tag",
//                MessageBuilder.withPayload(order.getOrderNo()).build(),
//                2000,
//                6 // 10秒
//        );


            //template.delete(key);
            //redisTemplate.delete(orderKey);
            return order.getOrderNo();
        }finally {
            if (lock.isLocked())lock.unlock();
        }

    }


}
